﻿using Microsoft.SqlServer.Server;
using SketchUpAPI.NET.Enums;
using SketchUpAPI.NET.SketchUp.Exception;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using static System.Net.Mime.MediaTypeNames;

namespace SketchUpAPI.NET.Objects
{
    /// <summary>
    /// 用于将 SketchUp 模型元素的纹理保存为文件。
    /// <para>对于 <see cref="Face"/> 对象来说，该类型在保存是修改非放射纹理，以便生成的纹理图像可以用于二维纹理坐标映射。</para>
    /// <para>修改后的UV坐标是由网格物体使用 SUMeshHelperRef 创建的</para>
    /// </summary>
    public class TextureWriter : ObjectBase
    {
        #region API 函数
        /// <summary>
        /// 创建一个 <see cref="TextWriter"/>
        /// </summary>
        /// <param name="writer"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUTextureWriterCreate(ref IntPtr writer);

        /// <summary>
        /// 释放资源
        /// </summary>
        /// <param name="writer"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUTextureWriterRelease(ref IntPtr writer);

        /// <summary>
        /// 从实体加载纹理
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="entity"><see cref="Entity"/> 实体</param>
        /// <param name="texture_id">纹理 Id</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUTextureWriterLoadEntity(IntPtr writer, IntPtr entity, out long texture_id);

        /// <summary>
        /// 从面加载纹理
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="face"><see cref="Face"/> 面</param>
        /// <param name="front_texture_id">正面纹理 Id</param>
        /// <param name="back_texture_id">背面纹理 Id</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUTextureWriterLoadFace(IntPtr writer, IntPtr face, out long front_texture_id, out long back_texture_id);

        /// <summary>
        /// 获取加载到当前写入器中的纹理个数
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUTextureWriterGetNumTextures(IntPtr writer, out long count);

        /// <summary>
        /// 将一个纹理写入到文件中
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="texture_id">纹理 Id</param>
        /// <param name="path">文件位置，扩展名必须是：jpg、bmp、tif 或 png</param>
        /// <param name="reduce_size">指示是否应通过缩放缩小纹理图像的大小。</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUTextureWriterWriteTexture(IntPtr writer, long texture_id, [MarshalAs(UnmanagedType.LPUTF8Str)] string path, bool reduce_size);

        /// <summary>
        /// 获取纹理图像
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="texture_id"></param>
        /// <param name="image"><see cref="ImageRep"/> 图像</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUTextureWriterGetImageRep(IntPtr writer, long texture_id, ref IntPtr image);

        /// <summary>
        /// 保存所有纹理
        /// </summary>
        /// <remarks>文件将使用原本的文件名和格式</remarks>
        /// <param name="writer"></param>
        /// <param name="directory">文件夹路径</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUTextureWriterWriteAllTextures(IntPtr writer, [MarshalAs(UnmanagedType.LPUTF8Str)] string directory);

        /// <summary>
        /// 判断纹理是否进行了仿射变换
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="texture_id"></param>
        /// <param name="is_affine"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUTextureWriterIsTextureAffine(IntPtr writer, long texture_id, out bool is_affine);

        /// <summary>
        /// 获取纹理贴图的路径
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="texture_id"></param>
        /// <param name="file_path"><see cref="StringRef"/> 纹理路径</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUTextureWriterGetTextureFilePath(IntPtr writer, long texture_id, ref IntPtr file_path);

        /// <summary>
        /// 获取面上的点对应的正面UV点
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="face"><see cref="Face"/> 面</param>
        /// <param name="len"><paramref name="points"/> 的个数</param>
        /// <param name="points">坐标点</param>
        /// <param name="uv_coords">UV点</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUTextureWriterGetFrontFaceUVCoords(IntPtr writer, IntPtr face, long len, Point3D[] points, ref Point2D[] uv_coords);

        /// <summary>
        /// 获取面上点对用背面UV点
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="face"><see cref="Face"/> 面</param>
        /// <param name="len"><paramref name="points"/> 的个数</param>
        /// <param name="points">坐标点</param>
        /// <param name="uv_coords">UV点</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUTextureWriterGetBackFaceUVCoords(IntPtr writer, IntPtr face, long len, Point3D[] points, ref Point2D[] uv_coords);

        /// <summary>
        /// 获取物体的纹理Id
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="entity"><see cref="Entity"/></param>
        /// <param name="texture_id"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUTextureWriterGetTextureIdForEntity(IntPtr writer, IntPtr entity, out long texture_id);

        /// <summary>
        /// 获取面的纹理Id
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="face"><see cref="Face"/></param>
        /// <param name="front">是否加载正面</param>
        /// <param name="texture_id"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUTextureWriterGetTextureIdForFace(IntPtr writer, IntPtr face, bool front, out long texture_id);
        #endregion

        /// <summary>
        /// 纹理总数
        /// </summary>
        public int Count
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUTextureWriterGetNumTextures(Id, out long count));
                return (int)count;
            }
        }

        public TextureWriter()
        {
            SketchUpExceptionHelper.ThrowSUResult(SUTextureWriterCreate(ref Id));
        }

        internal TextureWriter(IntPtr id) => Id = id;

        /// <summary>
        /// 加载物件纹理
        /// </summary>
        /// <param name="entity"></param>
        public void LoadEntityTexture(Entity entity, out long textureId)
        {
            SketchUpExceptionHelper.ThrowSUResult(SUTextureWriterLoadEntity(Id, entity.Id, out textureId));
        }

        /// <summary>
        /// 加载面上的纹理
        /// </summary>
        /// <param name="face"></param>
        /// <param name="frontTextureId"></param>
        /// <param name="backTextureId"></param>
        public void LoadFaceTexture(Face face, out long frontTextureId, out long backTextureId)
        {
            SketchUpExceptionHelper.ThrowSUResult(SUTextureWriterLoadFace(Id, face.Id, out frontTextureId, out backTextureId));
        }

        /// <summary>
        /// 获取纹理的图像
        /// </summary>
        /// <param name="textureId"></param>
        /// <returns></returns>
        public ImageRep GetTextureImageRep(long textureId)
        {
            ImageRep ir = new ImageRep();
            SketchUpExceptionHelper.ThrowSUResult(SUTextureWriterGetImageRep(Id, textureId, ref ir.Id));
            return ir;
        }

        /// <summary>
        /// 保存某个纹理
        /// </summary>
        /// <param name="textureId">纹理 Id</param>
        /// <param name="path">文件位置，扩展名必须是：jpg、bmp、tif 或 png</param>
        /// <param name="reduce_size">指示是否应通过缩放缩小纹理图像的大小。</param>
        public void SaveTexture(long textureId, string path, bool reduce_size)
        {
            SketchUpExceptionHelper.ThrowSUResult(SUTextureWriterWriteTexture(Id, textureId, path, reduce_size));
        }

        /// <summary>
        /// 保存所有纹理
        /// </summary>
        /// <remarks>每个纹理使用原始的文件名和后缀</remarks>
        /// <param name="directory">保存位置</param>
        public void SaveAllTexture(string directory)
        {
            SketchUpExceptionHelper.ThrowSUResult(SUTextureWriterWriteAllTextures(Id, directory));
        }

        /// <summary>
        /// 判断纹理是否经过了仿射变换
        /// </summary>
        /// <param name="textureId"></param>
        /// <returns></returns>
        public bool IsAffine(long textureId)
        {
            SketchUpExceptionHelper.ThrowSUResult(SUTextureWriterIsTextureAffine(Id, textureId, out bool isAffine));
            return isAffine;
        }

        /// <summary>
        /// 获取纹理的原始文件路径
        /// </summary>
        /// <param name="textureId"></param>
        /// <returns></returns>
        public string GetTextureFilePath(long textureId)
        {
            StringRef s = StringRef.Empty;
            SketchUpExceptionHelper.ThrowSUResult(SUTextureWriterGetTextureFilePath(Id, textureId, ref s.Id));
            return s.Dispose();
        }

        /// <summary>
        /// 获取面上的点对应的UV坐标
        /// </summary>
        /// <param name="face">面</param>
        /// <param name="isFront">是否获取正面</param>
        /// <param name="points">点</param>
        /// <returns></returns>
        public Point2D[] GetPointCorrespondingUV(Face face, bool isFront, params Point3D[] points)
        {
            Point2D[] uvs = new Point2D[points.Length];
            if (isFront)
            {
                SketchUpExceptionHelper.ThrowSUResult(SUTextureWriterGetFrontFaceUVCoords(Id, face.Id, points.Length, points, ref uvs));
            }
            else
            {
                SketchUpExceptionHelper.ThrowSUResult(SUTextureWriterGetBackFaceUVCoords(Id, face.Id, points.Length, points, ref uvs));
            }
            return uvs;
        }

        /// <summary>
        /// 获取物件纹理Id
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public long GetEntityTextureId(Entity entity)
        {
            SketchUpExceptionHelper.ThrowSUResult(SUTextureWriterGetTextureIdForEntity(Id, entity.Id, out long id));
            return id;
        }

        /// <summary>
        /// 获取一个面的纹理Id
        /// </summary>
        /// <param name="face">面</param>
        /// <param name="isFront">是否获取正面</param>
        /// <returns></returns>
        public long GetFaceTextureId(Face face, bool isFront)
        {
            SketchUpExceptionHelper.ThrowSUResult(SUTextureWriterGetTextureIdForFace(Id, face.Id, isFront, out long id));
            return id;
        }

        public override void Dispose()
        {
            SketchUpExceptionHelper.ThrowSUResult(SUTextureWriterRelease(ref Id));
        }
    }
}